﻿//Created by Action Script Viewer - http://www.buraks.com/asv
package Engine.Managers {
    import Engine.Classes.*;
    import flash.events.*;
    import Engine.Events.*;
    import Engine.Transactions.*;
    import flash.utils.*;

    public class TransactionManager extends EventDispatcher {

        public static const DEFAULT_MAX_QUEUED:int = 30;

        private static var m_maxQueued:int = 30;
        private static var m_amfMaxPerBatch:int = 8;
        private static var m_amfMaxWait:int = 5000;
        private static var m_amfMaxRetries:int = 4;
        private static var m_amfRetryAlertLimit:int = 1;
        private static var m_connection:AMFConnection;
        private static var m_transactions:Array = [];
        private static var m_batchedAmfCalls:Array = [];
        private static var m_sequenceNumber:int = 0;
        private static var m_amfBatchTimer:Timer = null;
        private static var m_retryTimer:Timer = null;
        private static var m_inactivityTimer:Timer = null;
        private static var m_ageOfOldestCall:Number = 0;
        private static var m_numBatchCalls:int = 0;
        private static var m_retrySequence:int = 0;
        private static var m_retryCount:int = 0;
        private static var m_instance:TransactionManager;
        protected static var m_lastFunc:String = "0";
        protected static var m_lastError:String = "0";
        protected static var m_inSync:Boolean = true;
        protected static var m_queueLimitExceeded:Boolean = false;
        private static var m_initialized:Boolean = false;
        private static var m_addtionalSignedParams:Object = {};

        public static function initialize():void{
            var _local2:String;
            var _local3:Transaction;
            var _local1:Object = GlobalEngine.zyParams;
            for (_local2 in _local1) {
                m_addtionalSignedParams[_local2] = _local1[_local2];
            };
            m_inactivityTimer = new Timer(Config.TRANSACTION_INACTIVITY_SECONDS);
            m_inactivityTimer.addEventListener(TimerEvent.TIMER, inactivityTimerComplete);
            m_inactivityTimer.start();
            while (m_transactions.length > 0) {
                _local3 = m_transactions.shift();
                _local3.endZaspLogging();
            };
            m_batchedAmfCalls = [];
            m_sequenceNumber = 0;
            m_retrySequence = 0;
            m_retryCount = 0;
            m_lastFunc = "0";
            m_lastError = "0";
            m_inSync = true;
            m_queueLimitExceeded = false;
            m_initialized = false;
        }
        public static function getInstance():TransactionManager{
            if (m_instance == null){
                m_instance = new (TransactionManager)();
            };
            return (m_instance);
        }
        public static function get lastError():String{
            return (m_lastError);
        }
        public static function get lastFunc():String{
            return (m_lastFunc);
        }
        public static function get inSync():Boolean{
            return (m_inSync);
        }
        public static function set inSync(_arg1:Boolean):void{
            m_inSync = _arg1;
            if (_arg1 == false){
                getInstance().dispatchEvent(new TransactionEvent(TransactionEvent.OUT_OF_SYNC));
            };
        }
        public static function set additionalSignedParams(_arg1:Object):void{
            m_addtionalSignedParams = _arg1;
        }
        public static function get additionalSignedParams():Object{
            return (m_addtionalSignedParams);
        }
        public static function addTransaction(_arg1:Transaction, _arg2:Boolean=false, _arg3:Boolean=false):void{
            if (_arg1.isInitTransaction() == true){
                m_initialized = true;
            };
            if (((!(canSendTransactions())) && (Config.DEBUG_MODE))){
                trace("Error: transaction added before transactions have been initialized.  This will fail on the back end.");
            };
            if (m_amfBatchTimer == null){
                m_amfBatchTimer = new Timer(1000);
                m_amfBatchTimer.addEventListener(TimerEvent.TIMER, onAmfBatchSend);
                m_amfBatchTimer.start();
            };
            if (inSync == true){
                _arg1.preAddTransaction();
                if (m_transactions.length == 0){
                    m_ageOfOldestCall = GlobalEngine.serverTime;
                };
                GlobalEngine.log("TransactionManager", ("Adding transaction " + getQualifiedClassName(_arg1)));
                m_transactions.push(_arg1);
                getInstance().dispatchEvent(new TransactionEvent(TransactionEvent.ADDED, _arg1));
                _arg1.startZaspLogging(_arg2, _arg3);
                if (_arg2 == true){
                    sendAllTransactions(false);
                } else {
                    if ((((m_transactions.length >= m_amfMaxPerBatch)) && ((m_batchedAmfCalls.length == 0)))){
                        if (_arg3){
                            GlobalEngine.log("TransactionManager", ("User blocking transaction queued without perform immediately " + getQualifiedClassName(_arg1)));
                        };
                        sendAllTransactions(true);
                    };
                };
                if ((((m_transactions.length >= m_maxQueued)) && ((m_queueLimitExceeded == false)))){
                    getInstance().dispatchEvent(new TransactionEvent(TransactionEvent.QUEUE_LIMIT_EXCEEDED));
                    m_queueLimitExceeded = true;
                };
                _arg1.postAddTransaction();
            } else {
                GlobalEngine.log("TransactionManager", "Suppressing transaction because we're oos");
            };
        }
        private static function incrementSequence():int{
            m_sequenceNumber++;
            return (m_sequenceNumber);
        }
        private static function generateSignedParams():Object{
            var _local2:*;
            var _local3:Object;
            var _local1:Object = new Object();
            for (_local2 in m_addtionalSignedParams) {
                _local1[_local2] = m_addtionalSignedParams[_local2];
            };
            _local3 = GlobalEngine.getFlashVar("flashRevision");
            _local1.flashRevision = null;
            if (_local3 != null){
                _local1.flashRevision = parseInt(_local3.toString());
            };
            return (_local1);
        }
        public static function batchCall(_arg1:Transaction, _arg2:String, _arg3:Array, _arg4:Function, _arg5:Function=null):void{
            var _local6:Object;
            var _local7:Object;
            var _local8:String;
            if (inSync){
                _local6 = {};
                _local6["stamp"] = GlobalEngine.serverTime;
                _local6["functionName"] = _arg2;
                _local6["params"] = _arg3;
                _local6["onSuccess"] = _arg4;
                _local6["onFailure"] = _arg5;
                _local6["transaction"] = _arg1;
                _local6["sequence"] = TransactionManager.incrementSequence();
                _local7 = _arg1.getBatchCallParams();
                for (_local8 in _local7) {
                    _local6[_local8] = _local7[_local8];
                };
                m_batchedAmfCalls.push(_local6);
            } else {
                ErrorManager.addError((("Unable to batch call because client is out-of-sync! (function: " + _arg2) + ")"));
            };
        }
        private static function onAmfBatchSend(_arg1:Event=null, _arg2:Boolean=false, _arg3:Boolean=false):void{
            var _local4:Number;
            var _local5:Object;
            var _local6:Array;
            var _local7:int;
            var _local8:TransactionBatchEvent;
            var _local9:Transaction;
            var _local10:Object;
            if ((((((m_batchedAmfCalls.length == 0)) && ((m_transactions.length > 0)))) || (_arg3))){
                _local4 = (GlobalEngine.serverTime - m_ageOfOldestCall);
                if ((((((m_ageOfOldestCall == 0)) || ((_local4 >= m_amfMaxWait)))) || ((_arg2 == true)))){
                    m_amfBatchTimer.stop();
                    while ((((m_transactions.length > 0)) && ((m_batchedAmfCalls.length < m_amfMaxPerBatch)))) {
                        _local9 = m_transactions.shift();
                        if (_local9.canPerform){
                            _local9.perform();
                            getInstance().dispatchEvent(new TransactionEvent(TransactionEvent.DISPATCHED, _local9));
                        };
                    };
                    GlobalEngine.log("AMFBatch", (("Executing " + m_batchedAmfCalls.length) + " in a batch"));
                    _local5 = TransactionManager.generateSignedParams();
                    _local6 = new Array();
                    _local7 = 0;
                    while (_local7 < m_batchedAmfCalls.length) {
                        _local10 = m_batchedAmfCalls[_local7];
                        _local6.push(_local10);
                        _local7++;
                    };
                    if (m_connection == null){
                        m_connection = new AMFConnection(onAmfBatchComplete, onAmfBatchFault);
                    };
                    m_connection.call.apply(m_connection, [GlobalEngine.engineOptions.baseService, _local5, _local6, m_retryCount]);
                    _local8 = new TransactionBatchEvent(TransactionBatchEvent.BATCH_DISPATCHED);
                    _local8.dispatchedBatchData = _local6;
                    getInstance().dispatchEvent(_local8);
                    m_ageOfOldestCall = GlobalEngine.serverTime;
                    m_amfBatchTimer.start();
                };
            };
        }
        private static function onAmfBatchComplete(_arg1:Object):void{
            var _local7:Array;
            var _local8:int;
            var _local9:Object;
            var _local10:Function;
            var _local2:Boolean;
            var _local3:int = Transaction.NO_ERROR;
            var _local4 = "batch";
            var _local5 = "";
            var _local6:TransactionBatchEvent = new TransactionBatchEvent(TransactionBatchEvent.BATCH_COMPLETE);
            _local6.responseBatchData = _arg1;
            getInstance().dispatchEvent(_local6);
            if (((!((_arg1 == null))) && ((_arg1.errorType == Transaction.NO_ERROR)))){
                m_inactivityTimer.stop();
                m_inactivityTimer.reset();
                m_inactivityTimer.start();
                _local7 = (_arg1.data as Array);
                if (((!((_local7 == null))) && ((_local7.length == m_batchedAmfCalls.length)))){
                    if (_arg1.zySig){
                        GlobalEngine.zyParams = _arg1.zySig;
                    };
                    _local8 = 0;
                    while (_local8 < _local7.length) {
                        _arg1 = _local7[_local8];
                        _local9 = {};
                        if (_arg1.errorType == Transaction.RETRY_TRANSACTION){
                            _local3 = _arg1.errorType;
                            _local5 = _arg1.errorData;
                            _local9 = m_batchedAmfCalls[0];
                            _local4 = _local9["functionName"];
                            _local2 = true;
                            break;
                        };
                        if (_arg1.errorType == Transaction.FORCE_RELOAD){
                            _local3 = _arg1.errorType;
                            _local5 = _arg1.errorData;
                            m_retryCount = (m_amfMaxRetries + 1);
                            _local2 = true;
                        } else {
                            _local9 = m_batchedAmfCalls.shift();
                            _local10 = _local9["onSuccess"];
                            _local10.apply(_local9["transaction"], [_arg1]);
                            if (m_numBatchCalls > 0){
                                m_numBatchCalls--;
                            };
                            getInstance().dispatchEvent(new TransactionEvent(TransactionEvent.COMPLETED, (_local9["transaction"] as Transaction)));
                        };
                        _local8++;
                    };
                    if (m_numBatchCalls > 0){
                        onAmfBatchSend(null, true);
                    };
                } else {
                    GlobalEngine.log("AMFBatch", ("ERROR - batch results is not an array of length " + m_batchedAmfCalls.length));
                };
            } else {
                if (_arg1 != null){
                    _local3 = _arg1.errorType;
                    _local5 = _arg1.errorData;
                    if ((((_local3 == Transaction.AUTH_NO_USER_ID)) || ((_local3 == Transaction.AUTH_NO_SESSION)))){
                        inSync = false;
                    } else {
                        if (_local3 == Transaction.OUTDATED_GAME_VERSION){
                            inSync = false;
                            getInstance().dispatchEvent(new TransactionEvent(TransactionEvent.VERSION_MISMATCH));
                        } else {
                            _local2 = true;
                        };
                    };
                } else {
                    _local3 = Transaction.RETRY_TRANSACTION;
                    _local2 = true;
                };
            };
            if (_local2 == true){
                m_lastError = _local3.toString();
                m_lastFunc = _local4;
                onAmfBatchFault(null, _local3, _local5);
            } else {
                if (m_retryCount > 0){
                    getInstance().dispatchEvent(new TransactionEvent(TransactionEvent.RETRY_SUCCESS));
                };
                m_retrySequence = 0;
                m_retryCount = 0;
            };
            if ((((m_transactions.length < m_maxQueued)) && (m_queueLimitExceeded))){
                getInstance().dispatchEvent(new TransactionEvent(TransactionEvent.QUEUE_LIMIT_NORMAL));
                m_queueLimitExceeded = false;
            };
        }
        private static function onAmfBatchFault(_arg1:Object, _arg2:int, _arg3:String):void{
            var _local4:Object;
            var _local5:Transaction;
            var _local6:Function;
            var _local7:Boolean;
            if (m_batchedAmfCalls.length){
                m_retrySequence = m_batchedAmfCalls[0].sequence;
                m_retryCount++;
                if (m_retryCount <= m_amfMaxRetries){
                    onRetryPause();
                    if (m_retryCount >= m_amfRetryAlertLimit){
                        getInstance().dispatchEvent(new TransactionFaultEvent(TransactionFaultEvent.RETRY, null, _arg2, _arg3));
                    };
                } else {
                    _local4 = m_batchedAmfCalls.shift();
                    _local5 = (_local4["transaction"] as Transaction);
                    if (_local5){
                        _local7 = _local5.isFaultable();
                        if (_local7){
                            getInstance().dispatchEvent(new TransactionFaultEvent(TransactionFaultEvent.FAULT, _local4["transaction"], _arg2, _arg3));
                            inSync = false;
                        };
                    };
                    _local6 = _local4["onFailure"];
                    _local6.apply(_local4["transaction"], [_arg1, _arg2, _arg3]);
                };
            };
            GlobalEngine.log("AMFBatch", ("Batch exec FAIL result = " + _arg1));
        }
        public static function sendAllTransactions(_arg1:Boolean):void{
            if (_arg1){
                m_numBatchCalls = m_transactions.length;
            };
            onAmfBatchSend(null, true);
        }
        private static function onRetryPause():void{
            var _local1:Number = (Math.pow(2, m_retryCount) * 1000);
            if (Config.DEBUG_MODE == true){
                _local1 = 1;
            };
            if (m_retryTimer == null){
                m_retryTimer = new Timer(_local1, 1);
                m_retryTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onRetrySend);
                m_retryTimer.start();
                GlobalEngine.log("AMFBatch", (("Waiting " + _local1) + "ms before retry"));
            };
        }
        private static function onRetrySend(_arg1:TimerEvent):void{
            if (m_retryTimer != null){
                m_retryTimer.stop();
                m_retryTimer = null;
            };
            GlobalEngine.log("AMFBatch", (((("Retrying transaction #" + m_retrySequence) + ". ") + m_retryCount) + " time(s)"));
            onAmfBatchSend(null, true, true);
        }
        public static function canSendTransactions():Boolean{
            return (m_initialized);
        }
        public static function disable():void{
            m_amfBatchTimer.stop();
        }
        public static function enable():void{
            m_amfBatchTimer.start();
        }
        private static function inactivityTimerComplete(_arg1:TimerEvent):void{
            getInstance().dispatchEvent(new TransactionEvent(TransactionEvent.INACTIVE));
        }
        public static function get transactionQueueLength():int{
            return (m_transactions.length);
        }
        public static function get maxQueued():int{
            return (m_maxQueued);
        }
        public static function get amfMaxPerBatch():int{
            return (m_amfMaxPerBatch);
        }
        public static function get amfMaxWait():int{
            return (m_amfMaxWait);
        }
        public static function get amfMaxRetries():int{
            return (m_amfMaxRetries);
        }
        public static function get amfRetryAlertLimit():int{
            return (m_amfRetryAlertLimit);
        }
        public static function set maxQueued(_arg1:int):void{
            m_maxQueued = _arg1;
        }
        public static function set amfMaxPerBatch(_arg1:int):void{
            m_amfMaxPerBatch = _arg1;
        }
        public static function set amfMaxWait(_arg1:int):void{
            m_amfMaxWait = _arg1;
        }
        public static function set amfMaxRetries(_arg1:int):void{
            m_amfMaxRetries = _arg1;
        }
        public static function set amfRetryAlertLimit(_arg1:int):void{
            m_amfRetryAlertLimit = _arg1;
        }

    }
}//package Engine.Managers 
